﻿using System;

namespace 复杂数据类型____Array
{
    class Program
    {
        static void Main(string[] args)
        {
            ArrayArr();
        }

        //数组：数据的组合，数据的集合，它必须是同一种数据类型
        // 指定一个类型 + 一组中括号 +变量名
        // 数组是引用类型
        // 数组的创建必须有初始值或者指定大小
        // 当指定了数组的大小，并且使用 {} 赋初始值时，初始值要写够这么多数据
        //  但制定了数组大小，但是没有使用{} 赋初始值时候，里面每一项是 这种数据类型的 默认值

        // default 关键字，在任何时候都代表这种类型的默认值
        // string 默认值是空字符串
        // int 默认值是 0 
        // 引用类型：默认值是 null
        // 数组默认值是：null ，数组也是引用类型

        static void TestArray()
        {
            //一. 数组的声明
            string[] personArr;
            string[] personArr0 = null;
            string[] personArr1 = default;
            string[] personArr2_0 = { };
            string[] personArr2 = { "aa", "bb", "cc" };
            string[] personArr3 = new string[2];
            string[] personArr4 = new string[3]
            {
                "dd",
                "33",
                "ee"
            };
            string[] personArr5 = new string[] { @"F:\Gitee\csharp-foundation", @"F:\Gitee\csharp-foundation" };
            int[] ageArr = new int[3]
            {
                11,
                22,
                33
            };

            string[] personArr22 =
             {
                @"F:\Gitee\csharp-foundation",
                @"F:\Gitee\csharp-foundation",
                "cc"
            };




            //2. 数组的使用
            //1. 如果数组赋值为 null ，你必须对数组赋有效值
            personArr1 = new string[2] { "张三", "李四" };

            //Console.WriteLine("personArr1.Rank "+personArr1.Rank); //返回 1

            // 2. 取数组指定位置的值
            string person = personArr1[1]; //通过索引取值，这句话里面的 “1” 就是索引，索引是 从 0 开始到 数组大小 - 1 的范围
            Console.WriteLine(person);

            // 3. 怎么把数据存储到数组
            personArr1[1] = "六六";
            Console.WriteLine(personArr1[1]);

            // 4. 确认在仅仅声明了数组大小的情况下，里面是什么

            Console.WriteLine($"Array3 - 1 = {personArr3[0]}  - {personArr3[0] == null} - {personArr3[0] == ""}");
            Console.WriteLine($"Age - 0 ={ageArr[0]} ");

            //三 . 在循环中遍历数组
            Console.WriteLine("----------- For ------------");
            for (int i = 0; i < personArr4.Length; i++)
            {
                Console.WriteLine(personArr4[i]); // For 循环内可以对集合的某一项进行赋值，Foreach 不行
            }
            Console.WriteLine("----------- Foreach------------");
            foreach (var item in personArr4)
            {
                Console.WriteLine(item);
            }

            Console.WriteLine("----------- while ------------");
            int count = personArr4.Length;
            while (--count >= 0)
            {
                Console.WriteLine(personArr4[count]);
            }

            Console.WriteLine("----------- do while ------------");
            int count0 = personArr4.Length - 1;
            do
            {
                Console.WriteLine(personArr4[count0]);// 只能写 count0 ，因为 count 作用域也在这里所以强调一下
                count0--;
            } while (count0 >= 0);
        }

        //二维数组
        // 二维数组其实就是数组的数组
        // 同一个维度的数组大小必须一致 (从图形上看，必须是一个正方形,类比棋盘)
        static void TestMultArray()
        {

            // 二维数组的声明
            int[,] iArr;
            int[,] iArr0 = null;
            int[,] iArr1 = default;
            int[,] iArr2 = new int[3, 3];
            int[,] iArr3 = new int[3, 2]
            {
                {1,2},
                {2,2 },
                { 3,3}
            };
            int[,] iArr4 =
             {
                {1,2,3,11},
                {4,5,6,33},
                {7,8,9,22},
            };

            string[,,] iiArr =
            {
                {{"AA","BB" },{"AA","BB"  },{"AA","BB"  } },
                {{"AA","BB" },{"AA","BB"  },{"AA","BB"  } },
                {{"AA","BB" },{"AA","BB"  },{"AA","BB"  } },
            };

            //二位数组的使用
            // 取值
            int age = iArr4[2, 2]; // 二维数组的取值，需要输入 “行列号”  ，取值范围也符合 “0 ”- “Lenght-1” 
            Console.WriteLine($"age = {age}");

            // 赋值
            iArr4[1, 1] = 101;
            Console.WriteLine($"Age = {iArr4[1, 1]}");

            // 读取维度属性
            // Rank 取值范围是 “0” - “逗号分割的个数”
            var rank = iArr4.Rank;

            //nameof 读取类型成员的名称 ，避免人工输入 出错    ，方便了调试       
            Console.WriteLine($"{nameof(TestMultArray)} - {nameof(iArr4)} 维度 = {rank}");
            Console.WriteLine($"{nameof(TestMultArray)} - {nameof(iiArr)} 维度 = {iiArr.Rank}");

            // 读取二维数组的 个数 ,是二维数组的数据总个数
            var lenght = iArr4.Length;
            Console.WriteLine($"{nameof(iArr4)} - 数据个数 = {lenght} ");

            // 遍历  ，需要用到嵌套 for 循环
            // 
            for (int i = 0; i < iArr4.Rank; i++)
            {
                var arrLenght1 = iArr4.GetLength(i);
                Console.WriteLine($"第 {i} 维的数组长度是 = {arrLenght1 }");
            }


            var arrLenght = iArr4.GetLength(0);
            var arrLenght0 = iArr4.GetLength(1);
            Console.WriteLine($"第 0 维的数组长度是 = {arrLenght }");
            Console.WriteLine($"第 1 维的数组长度是 = {arrLenght0 }");

            for (int i = 0; i < arrLenght; i++)
            {
                for (int j = 0; j < arrLenght0; j++)
                {
                    Console.WriteLine($"{nameof(iArr4)}[{i},{j}] = {iArr4[i, j]}");
                }
            }
        }


        // 交错数组 : 本质 就是数组中的值他还是数组 → 还是数组的数组
        //与多维数组区别在于：
        //1. 里面的数组长度不定，而多维数组必须大小一致
        //2. ageArrArr.Length 是数组本身的数据大小，在此处是 3 ,但是多维数组的 Length 是全部数据
        //3. 本质上还是一维数组 ， Rank = 1
        static void ArrayArr()
        {
            //数组的数组
            int[][] ageArrArr = new int[][]
             {
               new int[]{11,22 },
               new int[]{11,22 },
               new int[]{11,22,33 }, //跟多维数组比起来有个好处，能够存多个不同长度的数组
             };


            for (int i = 0; i < ageArrArr.Length; i++)
            {
                var ls = ageArrArr[i].Length;
                for (int j = 0; j < ls; j++)
                {
                    int value = ageArrArr[i][j];
                    Console.WriteLine($"第一个数组的第 {i} 个的值的第 {j} 个值是：{value}");
                }
            }

            Console.WriteLine($"第一个数组的第 3 个值第三个值是 ：{ageArrArr[2][2]}");

            //交错数组的声明：
            // 必须声明外围的数组的长度，不声明必报错：数组必须有大小或者有初始值
            int[][][] aaarr0 = new int[2][][];
            // 可以使用花括号表示，如果仅有一对花括号代表数组为空
            int[][][] aaarr1 = new int[][][] { };
            //报错：Index was outside the bounds of the array. 
            // Index 索引的意思
            // Bounds ： 边界
            // outside ： 在xxxx外面
            // 索引超出了数组的边界
            // 如果交错数组的里面是空数组，不能采用下面的方式赋值，因为会超索引
            //aaarr1[0][0] = new int[3] { 11, 12, 13 }; 
            //Console.WriteLine( aaarr1[0][0]);


            int[][][] aaarr2 = new int[][][]
            {
                new int [][]{ new int[] {11,22 }, new int[] { 33, 44 } },
                new int [][]{ new int[] {111,222 }, new int[] { 333, 444 } },
                new int [][]{ new int[] {11111,22222 }, new int[] { 3333, 4444 } }
            };

            // 测试输出 交错数组的 维度信息
            Console.WriteLine($"{nameof(ageArrArr)} 维度 = {ageArrArr.Rank}");
            Console.WriteLine($"{nameof(aaarr2)} 维度 = {aaarr2.Rank}");

            // 交错数组的 取值
            int value0 = aaarr2[1][1][0];
            Console.WriteLine($"第一个数组的第二个值的第二个值的第一个值 ： {value0}");
            Console.WriteLine($"Before : {aaarr2[2][0][1]}"); //before :之前
            // 交错数组的赋值
            aaarr2[2][0][1] = 55555;
            Console.WriteLine($"After : {aaarr2[2][0][1]}"); //After :之后

            // 交错数组的遍历
            for (int i = 0; i < aaarr2.Length; i++)
            {
                for (int j = 0; j < aaarr2[i].Length; j++) //aaarr2[i] 取数组的某一个值
                {
                    //aaarr2[i][j] 取交错数组的第 i 个值（数组）的第 j 个值
                    for (int k = 0; k < aaarr2[i][j].Length; k++)
                    {
                        Console.WriteLine($"第 {i + 1} 个数组的第 {j + 1} 个值的第 {k + 1} 个值是： {aaarr2[i][j][k]}");
                    }
                }
            }
        }

        // 三维数组
        static void TestSanArray()
        {
            //数组的声明 ： 在表示数组的中括号中使用 2个 逗号
            // 在此处，一对 花括号 代表一个数组
            int[,,] san =
            {
                {{1,2,3},{4,5,6 },{7,8,9 } },
                {{11,22,33},{44,55,66 },{77,88,99 } },
                {{111,222,333},{444,555,666 },{777,888,999 } },
            };

            // 取值
            int value = san[2, 1, 1];
            Console.WriteLine($"第三个值的第二个值的第二个值是： {value}");
            // 赋值
            Console.WriteLine($"Before : {san[2, 2, 1]}");
            san[2, 2, 1] = 66666;
            Console.WriteLine($"After : {san[2, 2, 1]}");
            // For 遍历
            int length0 = san.GetLength(0);
            int length1 = san.GetLength(1);
            int length2 = san.GetLength(2);
            for (int i = 0; i < length0; i++)
            {
                for (int j = 0; j < length1; j++)
                {
                    for (int k = 0; k < length2; k++)
                    {
                        Console.WriteLine($"第 {i + 1} 个值的 第 {j + 1} 个值的 第 {k + 1} 个值是{san[i, j, k]}");
                    }
                }
            }
            // Foreach 遍历
            foreach (var item in san)
            {
                Console.WriteLine("它的值是：" + item);
            }
        }

        static void TestSunSanArray()
        {
            int[,,] array3 =
           {
            {
                {10,11},{11,11},{12,11},{13,11}
            },

            {  {20,12},{21,12},{22,12},{23,12}
            },
                  {  {20,12},{21,12},{22,12},{23,12}
            },
            {
                {30,13},{31,13},{32,13},{33,1333}
            }

           };

            //Console.WriteLine(array3[3,4,2]); //证明了我分析的维度信息 Ok
            //Console.WriteLine(array3[2,3,1]); // 证明最远的距离数据获取 OK


            // 反面教材，第一个 for 循环遍历的个数写错了，应该是 GetLength(0)
            // 遍历的个数写死了
            for (int i = 0; i < array3.Rank; i++) 
            {
                for (int j = 0; j < 4; j++)
                {
                    for (int g = 0; g < 2; g++)
                    {
                        Console.WriteLine(array3[i, j, g]);
                    }
                }
            }

            Console.WriteLine( "--------------- 分割 -------------");
            foreach (var item in array3)
            {
                Console.WriteLine(item);
            }
        }

    }
}
